package software.lib.server;

import javafx.util.Pair;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.springframework.mock.web.MockFilterConfig;
import org.springframework.mock.web.MockServletConfig;
import org.springframework.mock.web.MockServletContext;

import javax.servlet.*;
import javax.servlet.annotation.HandlesTypes;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebListener;
import javax.servlet.annotation.WebServlet;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * Created by Wang on 2017/5/15.
 */
public class HttpServer {
    public static void main(String[] args){
        ChannelFactory factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),Executors.newCachedThreadPool());
        ServerBootstrap bootstrap = new ServerBootstrap(factory);
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            ServletContext servletContext = new MockServletContext();
            FilterConfig filterConfig = new MockFilterConfig(servletContext);
            MockServletConfig servletConfig = new MockServletConfig(servletContext);
            Map<String,Servlet> servletMap = new TreeMap<>();
            List<Pair<String,Filter>> filters = new ArrayList<>();
            {
                List<Class> beanlist = BeanScanner.scannerJar(".","org.springframework");

                //Initialize
                beanlist.parallelStream().filter(cls->cls.isAnnotationPresent(HandlesTypes.class))
                        .forEach(cls -> {
                            try {
                                ServletContainerInitializer initializer = (ServletContainerInitializer) cls.newInstance();
                                HandlesTypes handlesTypes = (HandlesTypes) cls.getAnnotation(HandlesTypes.class);

                                Set<Class<?>> handleSet = beanlist.parallelStream().filter(handCls->{
                                    for (Class cc:handlesTypes.value()) {
                                        if(handCls.isAnnotationPresent(cc))
                                            return true;
                                    }
                                    return false;
                                }).collect(Collectors.toSet());
                                initializer.onStartup(handleSet,servletContext);
                            } catch (InstantiationException e) {
                                e.printStackTrace();
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (ServletException e) {
                                e.printStackTrace();
                            }
                        });

                //创建对象
                beanlist.parallelStream().filter(cls->cls.isAnnotationPresent(WebServlet.class)||cls.isAnnotationPresent(WebFilter.class)||cls.isAnnotationPresent(WebListener.class))
                        .forEach(cls->{
                            if(cls.isAnnotationPresent(WebServlet.class)){
                                try {
                                    Servlet servlet = (Servlet) cls.newInstance();
                                    WebServlet webServlet = (WebServlet) cls.getAnnotation(WebServlet.class);
                                    String[] urlpattern = webServlet.urlPatterns();
                                    Arrays.stream(urlpattern).forEach(s -> servletMap.put(s,servlet));
                                } catch (InstantiationException e) {
                                    e.printStackTrace();
                                } catch (IllegalAccessException e) {
                                    e.printStackTrace();
                                }
                            }

                            if(cls.isAnnotationPresent(WebFilter.class)){
                                try {
                                    Filter filter = (Filter) cls.newInstance();
                                    WebFilter webFilter = (WebFilter) cls.getAnnotation(WebFilter.class);
                                    String[] urlpattern = webFilter.urlPatterns();
                                    Arrays.stream(urlpattern).map(x->new Pair<String,Filter>(x,filter)).forEach(filters::add);
                                } catch (InstantiationException e) {
                                    e.printStackTrace();
                                } catch (IllegalAccessException e) {
                                    e.printStackTrace();
                                }
                            }

                            if(cls.isAnnotationPresent(WebListener.class)){
                                WebListener webFilter = (WebListener) cls.getAnnotation(WebListener.class);
                                //TODO Lisener 自动加载
                            }
                        });


                //Initialize Servlet and Filter, call init()
                servletMap.values().stream().sorted(Comparator.comparingInt(servlet -> {
                    WebServlet webServlet = servlet.getClass().getAnnotation(WebServlet.class);
                    if(webServlet!=null)
                        return webServlet.loadOnStartup();
                    return -1;
                }).reversed()).forEach(servlet -> {
                    try {
                        servlet.init(servletConfig);
                    } catch (ServletException e) {
                        e.printStackTrace();
                    }
                });

                filters.stream().map(pair->pair.getValue()).forEach(filter -> {
                    try {
                        filter.init(filterConfig);
                    } catch (ServletException e) {
                        e.printStackTrace();
                    }
                });
            }
            @Override
            public ChannelPipeline getPipeline() throws Exception {
                return Channels.pipeline(new ServerChannelHandler(servletMap,filters));
            }
        });
        bootstrap.setOption("tcpNoDelay", true);
        bootstrap.setOption("keepAlive", true);
        bootstrap.bind(new InetSocketAddress(8080));
    }
}
